﻿using Chromium.Remote;
using Chromium.WebBrowser;
using M5.GeminiHybird.Core.Attribute;
using M5.GeminiHybird.Core.Config;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;

namespace M5.GeminiHybird.Core.Builder
{
    internal class JavascriptBuilder
    {

        private M5WebBrowser _m5WebBrowser { get; set; }


        internal JavascriptBuilder(M5WebBrowser m5WebBrowser)
        {
            _m5WebBrowser = m5WebBrowser;
        }

        /// <summary>
        /// 配置Javascript
        /// </summary>
        internal void Config()
        {

            //bool a = _m5WebBrowser.ExecuteJavascript("var qqq = 12;");
            //加入全局js对象
            JSObject m5Obj = _m5WebBrowser.GlobalObject.AddObject(JavascriptConfig.Instance.JavascriptRootName);

            //获取可执行文件的程序集信息
            Assembly exeAssem = Assembly.GetEntryAssembly();
            //最后需要添加到js对象上的类型集合
            List<Type> executeClassTypes = new List<Type>();
            //该程序集所有的类型集合
            List<Type> allTypes = new List<Type>(exeAssem.GetTypes());

            //获取该程序集所有的Name信息
            var allAssembly = Assembly.GetEntryAssembly().GetReferencedAssemblies();

            //不进行搜索的程序集名称
            string[] notSearchAssembly = new string[] {
                "mscorlib", "System","System.Windows.Forms","System.Drawing"
            };
            //反射添加所有类型集合
            foreach (var assem in allAssembly)
            {
                //排除不搜索的程序集
                if (notSearchAssembly.Contains(assem.Name))
                {
                    continue;
                }
                Type[] tts = Assembly.Load(assem.FullName).GetTypes();
                allTypes.AddRange(tts);
            }

            //添加js对象程序集集合
            foreach (Type type in allTypes)
            {
                if (type.BaseType == typeof(JavascriptEvent.BaseJavescriptEvent))
                {
                    executeClassTypes.Add(type);
                }
            }

            //构建Js对象
            foreach (var executeType in executeClassTypes)
            {
                //当前类型名称
                string typeName = executeType.Name.Substring(0, 1).ToLower() + executeType.Name.Substring(1);

                //移除event
                typeName = typeName.Remove(typeName.LastIndexOf("Event"));

                //添加Js对象
                var m5ChildObj = m5Obj.AddObject(typeName);

                //反射一个当前类型实例
                object instanceObj = executeType.Assembly.CreateInstance(executeType.FullName);
                var baseEvent = (instanceObj as JavascriptEvent.BaseJavescriptEvent);
                //获取所有方法
                var methods = instanceObj.GetType().GetMethods();
                foreach (var method in methods)
                {
                    //看是否包含js方法属性
                    if (!JavascriptMethodAttribute.HasThisAttribute(method))
                        continue;

                    string methodJsName = method.Name.Substring(0, 1).ToLower() + method.Name.Substring(1);
                    //添加映射
                    baseEvent.CSharpAndJsFunNamesPairs.Add(m5ChildObj.Name + "." +methodJsName , method.Name);
                    //js对象上添加方法
                    m5ChildObj.AddFunction(methodJsName).Execute += baseEvent.CommonJavascript_Filter;
                }
            }

            //构建js对象上的一些属性
            RootJavascriptPropertyBuilder(m5Obj);
        }

        

        private void RootJavascriptPropertyBuilder(JSObject m5Obj)
        {
            //获取Js配置类的属性
            var ps = JavascriptConfig.Instance.GetType().GetProperties();

            foreach (var item in ps)
            {
                //是否需要添加
                if(!CanReflectionAttribute.HasThisAttribute(item))
                {
                    continue;
                }
                //attrs[0] == M5.GeminiHybird.Core.Attribute.NoReflectionAttribute.

                //给JS对象添加属性
                var version = m5Obj.AddDynamicProperty(item.Name);

                //添加属性的GET方法(只读)
                version.PropertyGet += (prop, args) =>
                {
                    args.Retval = CfrV8Value.CreateString(item.GetValue(JavascriptConfig.Instance, null).ToString());
                    args.SetReturnValue(true);
                };
            }
        }
    }
}
